package com.pro01.tracker.controller;

import com.pro01.tracker.service.TrackerService;
import com.pro01.tracker.utils.PeerEncoder;
import com.pro01.tracker.utils.bencode.BEValue;
import com.pro01.tracker.utils.bencode.BEncoder;
import com.pro01.tracker.utils.AnnounceParser;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.*;

@RestController
@RequestMapping("/announce")
public class AnnounceController {

    @Autowired
    private TrackerService trackerService;

    @GetMapping
    public ResponseEntity<byte[]> announce(
            @RequestParam("peer_id") String peerId,
            @RequestParam("port") int port,
            @RequestParam("uploaded") long uploaded,
            @RequestParam("downloaded") long downloaded,
            @RequestParam("left") long left,
            @RequestParam(value = "event", required = false, defaultValue = "update") String event,
            @RequestParam(value = "passkey", required = false) String passkey,
            HttpServletRequest request
    ) {
        try {
            String ip = request.getRemoteAddr();
            byte[] infoHashBytes = extractInfoHashFromRequest(request);
            if (infoHashBytes == null || infoHashBytes.length != 20) {
                System.out.println("⚠️ 解析 info_hash 失败！");
                return failureResponse("Invalid info_hash format");
            }

            String infoHash = AnnounceParser.toHex(infoHashBytes).toLowerCase();

            System.out.println("===== Tracker 收到请求 =====");
            System.out.println("IP = " + ip);
            System.out.println("info_hash(hex) = " + infoHash);
            System.out.println("peer_id = " + peerId);
            System.out.println("port = " + port);
            System.out.println("uploaded = " + uploaded + ", downloaded = " + downloaded + ", left = " + left);
            System.out.println("event = " + event);
            System.out.println("passkey = " + passkey);

            List<String> hashes = trackerService.getAllInfoHashes(); // 新加
            System.out.println("📋 数据库中的 info_hash 列表:");
            hashes.forEach(System.out::println);

            Long torrentId = trackerService.getTorrentIdByInfoHash(infoHash);
            if (torrentId == null) {
                System.out.println("❌ 找不到该种子：" + infoHash);
                return failureResponse("Torrent not found");
            }
            System.out.println("找到 torrentId = " + torrentId);

//            String role = (left == 0) ? "SEEDER" : "LEECHER";
            String role;
            if (left > 0) {
                role = "LEECHER"; // 下载未完成
            } else {
                role = (uploaded > 0) ? "SEEDER" : "LEECHER"; // 下载完成但没上传不算种子者
            }
            System.out.println("推断角色 = " + role);


            if (passkey == null || passkey.isEmpty()) {
                System.out.println("⚠️ 匿名请求（无 passkey），不记录上传/下载");
            } else {
                Long userId = trackerService.getUserIdByPasskey(passkey);
                if (userId == null) {
                    System.out.println("❌ passkey 无效：" + passkey);
                    return failureResponse("Invalid passkey");
                }
                System.out.println("用户 ID = " + userId + "，记录上传/下载行为");
                trackerService.handleAnnounce(userId, torrentId, peerId, ip, port, role, uploaded, downloaded, event.toUpperCase());
            }

            List<PeerEncoder.PeerInfo> peerList = trackerService.getPeersForTorrent(torrentId);
            byte[] peersCompact = PeerEncoder.compactPeers(peerList);
            System.out.println("返回 peers 个数 = " + peerList.size());
            System.out.println("===== Tracker 请求完成 =====");

            Map<String, BEValue> response = new HashMap<>();
            response.put("interval", new BEValue(1800));
            response.put("complete", new BEValue(0));
            response.put("incomplete", new BEValue(0));
            response.put("peers", new BEValue(peersCompact));

            ByteBuffer buffer = BEncoder.bencode(response);
            return ResponseEntity
                    .ok()
                    .header(HttpHeaders.CONTENT_TYPE, "application/octet-stream")
                    .body(buffer.array());

        } catch (Exception e) {
            e.printStackTrace();
            return failureResponse("Internal error: " + e.getMessage());
        }
    }

    private byte[] extractInfoHashFromRequest(HttpServletRequest request) {
        try {
            String query = request.getQueryString();
            int index = query.indexOf("info_hash=");
            if (index == -1) return null;

            int start = index + "info_hash=".length();
            int end = query.indexOf("&", start);
            String encoded = (end == -1) ? query.substring(start) : query.substring(start, end);

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            for (int i = 0; i < encoded.length(); ) {
                char c = encoded.charAt(i);
                if (c == '%') {
                    String hex = encoded.substring(i + 1, i + 3);
                    out.write(Integer.parseInt(hex, 16));
                    i += 3;
                } else {
                    out.write((byte) c);
                    i++;
                }
            }
            return out.toByteArray();
        } catch (Exception e) {
            return null;
        }
    }

    private ResponseEntity<byte[]> failureResponse(String reason) {
        try {
            Map<String, BEValue> failure = new HashMap<>();
            failure.put("failure reason", new BEValue(reason));
            ByteBuffer buffer = BEncoder.bencode(failure);
            return ResponseEntity
                    .status(HttpStatus.BAD_REQUEST)
                    .header(HttpHeaders.CONTENT_TYPE, "application/octet-stream")
                    .body(buffer.array());
        } catch (Exception e) {
            return ResponseEntity.status(500).build();
        }
    }
}
